package wiki.xsx.core.bytecode.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import wiki.xsx.core.bytecode.enums.AnnotationType;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 注解
 *
 * @author xsx
 * @date 2023/2/1
 * @since 1.8
 * <p>
 * Copyright (c) 2023 xsx All Rights Reserved.
 * x-easypdf is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * </p>
 */
@Data
public class Annotations {

    /**
     * 名称
     */
    private String name;
    /**
     * 策略
     */
    private Policy policy;
    /**
     * 属性
     */
    private List<Attribute> attributes;

    /**
     * 有参构造
     *
     * @param name 名称
     */
    public Annotations(String name) {
        this(name, Policy.RuntimeVisible);
    }

    /**
     * 有参构造
     *
     * @param name   名称
     * @param policy 策略
     */
    public Annotations(String name, Policy policy) {
        this(name, policy, new ArrayList<>(0));
    }

    /**
     * 有参构造
     *
     * @param name       名称
     * @param attributes 属性列表
     */
    public Annotations(String name, Attribute... attributes) {
        this(name, Policy.RuntimeVisible, attributes);
    }

    /**
     * 有参构造
     *
     * @param name       名称
     * @param attributes 属性列表
     */
    public Annotations(String name, List<Attribute> attributes) {
        this(name, Policy.RuntimeVisible, attributes);
    }

    /**
     * 有参构造
     *
     * @param name       名称
     * @param policy     策略
     * @param attributes 属性列表
     */
    public Annotations(String name, Policy policy, Attribute... attributes) {
        this.name = name;
        this.policy = Optional.ofNullable(policy).orElse(Policy.RuntimeVisible);
        this.attributes = Optional.ofNullable(attributes)
                .map(v -> Arrays.stream(attributes).collect(Collectors.toList()))
                .orElse(new ArrayList<>(0));
    }

    /**
     * 有参构造
     *
     * @param name       名称
     * @param policy     策略
     * @param attributes 属性列表
     */
    public Annotations(String name, Policy policy, List<Attribute> attributes) {
        this.name = name;
        this.policy = Optional.ofNullable(policy).orElse(Policy.RuntimeVisible);
        this.attributes = Optional.ofNullable(attributes).orElse(new ArrayList<>(0));
    }

    /**
     * 策略
     */
    @Getter
    public enum Policy {
        /**
         * 运行时可见
         */
        RuntimeVisible(),
        /**
         * 运行时不可见
         */
        RuntimeInvisible();
    }

    /**
     * 属性
     */
    @Data
    @AllArgsConstructor
    public static class Attribute {
        /**
         * 类型
         */
        private AnnotationType type;
        /**
         * 名称
         */
        private String name;
        /**
         * 值
         * <p>注：当type=AnnotationType.ARRAY时，该值为List<Annotations.Attribute>类型</p>
         */
        private Object value;
    }
}
